/**
 * Keypad
 * 
 * @author  Bruno Miguel de Oliveira Tamer <bmotamer@gmail.com>
 * @version 2012.02.13
 */

#region Unity Libraries
using UnityEngine;
#endregion

/// <summary> Handles the current state of the keyboard </summary>
public static class Keypad
{
	
	#region Constants
	/// <summary> Flag what represents the key is released </summary>
	private const int c_Untouched = 0;
	/// <summary> Flag what represents the key was just pressed </summary>
	private const int c_Triggered = 1;
	/// <summary> Flag what represents the key is being pressed </summary>
	private const int c_Pressed	 = 2;
	/// <summary> Flag what represents the key was just released </summary>
	private const int c_Released  = 3;
	#endregion
	
	#region Read-only
	/// <summary> Key state container </summary>
	private static readonly int[] s_State 	 = new int[256];
	#endregion
	
	#region Main
	/// <summary> Static constructor </summary>
	static Keypad()
	{
		// Loops around all the keys of the keyboard
		for (int i = 0; i < 256; i++)
			// If the key is down, just consider its state as pressed, otherwise, untouched
			s_State[i] = Input.GetKey((KeyCode)i) ? c_Pressed : c_Untouched;
	}
	/// <summary> Updates the state of all the keys </summary>
	public static void Update()
	{
		// Loops around all the keys of the keyboard
		for (int i = 0; i < 256; i++)
			/**
			 * If the key is down, and it was up before, consider its state as triggered, otherwise, pressed.
			 * But if it is up and before it was up too, consider its state as untouched, otherwise, released
			 */
			s_State[i]  = Input.GetKey((KeyCode)i) ? IsUp(i) ? c_Triggered : c_Pressed : IsUp(i) ? c_Untouched : c_Released;
	}
	#endregion
	
	#region State Accessors
	
	#region Via int
	/// <summary> Checks if a key is untouched </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is untouched </returns>
	public static bool IsUntouched(int key) { return s_State[key] == c_Untouched; }
	/// <summary> Checks if a key is triggered </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is triggered </returns>
	public static bool IsTriggered(int key) { return s_State[key] == c_Triggered; }
	/// <summary> Checks if a key is pressed </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is pressed </returns>
	public static bool IsPressed(int key) { return s_State[key] == c_Pressed; }
	/// <summary> Checks if a key is released </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is released </returns>
	public static bool IsReleased(int key) { return s_State[key] == c_Released; }
	/// <summary> Checks if a key is up </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is untouched or released </returns>
	public static bool IsUp(int key) { return s_State[key] == c_Untouched || s_State[key] == c_Released; }
	/// <summary> Checks if a key is down </summary>
	/// <param name="key"> A <see cref="System.Int32"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state isn't up </returns>
	public static bool IsDown(int key) { return !IsUp(key); }
	#endregion
	
	#region Via KeyCode
	public static bool IsUntouched(KeyCode key) { return s_State[(int)key] == c_Untouched; }
	/// <summary> Checks if a key is triggered </summary>
	/// <param name="key"> A <see cref="KeyCode"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is triggered </returns>
	public static bool IsTriggered(KeyCode key) { return s_State[(int)key] == c_Triggered; }
	/// <summary> Checks if a key is pressed </summary>
	/// <param name="key"> A <see cref="KeyCode"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is pressed </returns>
	public static bool IsPressed(KeyCode key) { return s_State[(int)key] == c_Pressed; }
	/// <summary> Checks if a key is released </summary>
	/// <param name="key"> A <see cref="KeyCode"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is released </returns>
	public static bool IsReleased(KeyCode key) { return s_State[(int)key] == c_Released; }
	/// <summary> Checks if a key is up </summary>
	/// <param name="key"> A <see cref="KeyCode"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state is untouched or released </returns>
	public static bool IsUp(KeyCode key) { return s_State[(int)key] == c_Untouched || s_State[(int)key] == c_Released; }
	/// <summary> Checks if a key is down </summary>
	/// <param name="key"> A <see cref="KeyCode"/> Key code </param>
	/// <returns> A <see cref="System.Boolean"/> If its state isn't up </returns
	public static bool IsDown(KeyCode key) { return !IsUp((int)key); }
	#endregion
	
	#region Util
	
	// TODO: anyKey
	
	#endregion
	
	#endregion
	
}